<!doctype html>
<!--
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<html>
  <head>
    <title>publish attributes</title>
    <script src="../../../webcomponentsjs/webcomponents.js"></script>
    <link rel="import" href="../../polymer.html">
    <script src="../../../tools/test/htmltest.js"></script>
    <script src="../../../tools/test/chai/chai.js"></script>
  </head>
  <body>

    <x-basic></x-basic>
    <polymer-element name="x-basic" attributes="nog" noscript>
    </polymer-element>

    <x-attr-publish></x-attr-publish>
    <polymer-element name="x-attr-publish" attributes="nog">
      <script>
        Polymer('x-attr-publish', {
          publish: {
            nog: {value: '', reflect: false}
          }
        });
      </script>
    </polymer-element>

    <x-foo></x-foo>
    <polymer-element name="x-foo">
      <script>
        Polymer('x-foo', {
          publish: {
            foo: {value: '', reflect: true},
            baz: {value: '', reflect: true},
            def1: {reflect: true},
            def2: {reflect: true}
          }
        });
      </script>
    </polymer-element>

    <x-bar></x-bar>
    <polymer-element name="x-bar" extends="x-foo">
      <script>
        Polymer('x-bar', {
          publish: {
            zot: {value: 3, reflect: true},
            zim: {value: false, reflect: true},
            str: {value: 'str', reflect: true},
            obj: {reflect: true}
          }
        });
      </script>
    </polymer-element>

    <x-zot></x-zot>
    <polymer-element name="x-zot" extends="x-bar">
      <script>
        Polymer('x-zot', {
          publish: {
            zot: {value: 2, reflect: false},
            str: 'str2'
          }
        });
      </script>
    </polymer-element>
    
    <x-compose></x-compose>
    <polymer-element name="x-compose">
      <template>
        <x-bar id="bar" zim="{{zim}}"></x-bar>
      </template>
      <script>
        Polymer('x-compose', {
          zim: false
        });
      </script>
    </polymer-element>

  <script>
      var assert = chai.assert;
      function oneMutation(node, options, cb) {
        var o = new MutationObserver(function() {
          cb();
          o.disconnect();
        });
        o.observe(node, options);
      }
      
      document.addEventListener('polymer-ready', function() {
        var xbasic = document.querySelector('x-basic');
        assert.equal(xbasic.nog, undefined, 'property published with `attributes` has correct initial value');
        xbasic.setAttribute('nog', 'hi');
        assert.equal(xbasic.nog, 'hi', 'deserialization of property published via `attributes`');

        var xattrpublish = document.querySelector('x-attr-publish');
        assert.equal(xattrpublish.nog, '', 'property published with `attributes` has correct initial value');
        xattrpublish.setAttribute('nog', 'hi');
        assert.equal(xattrpublish.nog, 'hi', 'deserialization of property published via `attributes`');

        var xcompose = document.querySelector('x-compose');
        var xfoo = document.querySelector('x-foo');
        assert.equal(xfoo.foo, '', 'property published with info object has correct initial value');
        xfoo.foo = 5;
        xfoo.setAttribute('def1', '15');
        xfoo.def2 = 15;
        //
        assert.isFalse(xcompose.$.bar.hasAttribute('zim'), 'attribute bound to property updates when binding is made');
        assert.equal(xfoo.getAttribute('def2'), '15', 'default valued published property reflects to attr');
        assert.equal(xfoo.def1, '15', 'attr updates default valued published property');
        assert.equal(String(xfoo.foo), xfoo.getAttribute('foo'), 'attribute reflects property as string');
        xfoo.setAttribute('foo', '27');
        assert.equal(xfoo.foo, xfoo.getAttribute('foo'), 'property reflects attribute');
        //
        xfoo.baz = 'Hello';
        //
        assert.equal(xfoo.baz, xfoo.getAttribute('baz'), 'attribute reflects property');
        //
        var xbar = document.querySelector('x-bar');
        assert.equal(xbar.zim, false, 'property published with info object has correct initial value');
        assert.equal(xbar.foo, '', 'property published with info object has correct initial value');
        //
        xbar.foo = 'foo!';
        xbar.zot = 27;
        xbar.zim = true;
        xbar.str = 'str!';
        xbar.obj = {hello: 'world'};
        //
        assert.equal(xbar.foo, xbar.getAttribute('foo'), 'inherited published property is reflected');
        assert.equal(String(xbar.zot), xbar.getAttribute('zot'), 'attribute reflects property as number');
        assert.equal(xbar.getAttribute('zim'), '', 'attribute reflects true valued boolean property as having attribute');
        assert.equal(xbar.str, xbar.getAttribute('str'), 'attribute reflects property as published string');
        assert.isFalse(xbar.hasAttribute('obj'), 'attribute does not reflect object property');
        //
        xbar.setAttribute('zim', 'false');
        xbar.setAttribute('foo', 'foo!!');
        xbar.setAttribute('zot', 54);
        xbar.setAttribute('str', 'str!!');
        xbar.setAttribute('obj', "{'hello': 'world'}");
        //
        assert.equal(xbar.foo, xbar.getAttribute('foo'), 'property reflects attribute as string');
        assert.equal(xbar.zot, 54, 'property reflects attribute as number');
        assert.equal(xbar.zim, false, 'property reflects attribute as boolean');
        assert.equal(xbar.str, 'str!!', 'property reflects attribute as published string');
        assert.deepEqual(xbar.obj, {hello: 'world'}, 'property reflects attribute as object');
        //
        xbar.zim = false;
        //
        assert.isFalse(xbar.hasAttribute('zim'), 'attribute reflects false valued boolean property as NOT having attribute');
        //
        var objAttr = xbar.getAttribute('obj');
        oneMutation(xbar, {attributes: true}, function() {  
          assert.equal(xbar.getAttribute('obj'), 'hi', 'reflect property based on current type');
          //assert.isFalse(xbar.hasAttribute('obj'), 'property with default type of object does not serialize');
          done();
        });
        //
        var xzot = document.querySelector('x-zot');
        assert.equal(xzot.str, 'str2');
        xzot.str = 'hello';
        assert.equal(xzot.getAttribute('str'), xzot.str);
        //
        assert.equal(xzot.zot, 2);
        xzot.zot = 5;
        assert.isFalse(xzot.hasAttribute('zot'), 'extendee reflect false not honored');
        //
        xbar.obj = 'hi';
        // trigger a mutation to watch
        xbar.setAttribute('dummy', 'dummy');
        // 
        // don't let observe polyfill wait, flush asap
        Platform.flush();
      });
    </script>
  </body>
</html>
